Svg.VERSION = 1.0;
Svg.NAMESPACE = "http://www.w3.org/2000/svg";

function Svg() {
}

PathParser.PARAMCOUNT = {A: 7, C: 6, H: 1, L: 2, M: 2, Q: 4, S: 4, T: 2, V: 1, Z: 0};
PathParser.METHODNAME = {
  A: "arcAbs",
  a: "arcRel",
  C: "curvetoCubicAbs",
  c: "curvetoCubicRel",
  H: "linetoHorizontalAbs",
  h: "linetoHorizontalRel",
  L: "linetoAbs",
  l: "linetoRel",
  M: "movetoAbs",
  m: "movetoRel",
  Q: "curvetoQuadraticAbs",
  q: "curvetoQuadraticRel",
  S: "curvetoCubicSmoothAbs",
  s: "curvetoCubicSmoothRel",
  T: "curvetoQuadraticSmoothAbs",
  t: "curvetoQuadraticSmoothRel",
  V: "linetoVerticalAbs",
  v: "linetoVerticalRel",
  Z: "closePath",
  z: "closePath"
}

function PathParser() {
  this._lexer = new PathLexer();
  this._handler = null;
}

PathParser.prototype.parsePath = function (path) {
  if (path == null || path.namespaceURI != Svg.NAMESPACE || path.localName != "path") throw new Error("PathParser.parsePath: The first parameter must be an SVG path element");
  this.parseData(path.getAttributeNS(null, "d"));
};
PathParser.prototype.parseData = function (pathData) {
  if (typeof (pathData) != "string") throw new Error("PathParser.parseData: The first parameter must be a string");
  if (this._handler != null && this._handler.beginParse != null) this._handler.beginParse();
  var lexer = this._lexer;
  lexer.setPathData(pathData);
  var mode = "BOP";
  var token = lexer.getNextToken();
  while (!token.typeis(PathToken.EOD)) {
    var param_count;
    var params = new Array();
    switch (token.type) {
      case PathToken.COMMAND:
        if (mode == "BOP" && token.text != "M" && token.text != "m") throw new Error("PathParser.parseData: a path must begin with a moveto command");
        mode = token.text;
        param_count = PathParser.PARAMCOUNT[token.text.toUpperCase()];
        token = lexer.getNextToken();
        break;
      case PathToken.NUMBER:
        break;
      default:
        throw new Error("PathParser.parseData: unrecognized token type: " + token.type);
    }
    for (var i = 0; i < param_count; i++) {
      switch (token.type) {
        case PathToken.COMMAND:
          throw new Error("PathParser.parseData: parameter must be a number: " + token.text);
        case PathToken.NUMBER:
          params[i] = token.text - 0;
          break;
        default:
          throw new Errot("PathParser.parseData: unrecognized token type: " + token.type);
      }
      token = lexer.getNextToken();
    }
    if (this._handler != null) {
      var handler = this._handler;
      var method = PathParser.METHODNAME[mode];
      if (handler[method] != null) handler[method].apply(handler, params);
    }
    if (mode == "M") mode = "L";
    if (mode == "m") mode = "l";
  }
};
PathParser.prototype.setHandler = function (handler) {
  this._handler = handler;
};
PathLexer.VERSION = 1.0;

function PathLexer(pathData) {
  if (pathData == null) pathData = "";
  this.setPathData(pathData);
}

PathLexer.prototype.setPathData = function (pathData) {
  if (typeof (pathData) != "string") throw new Error("PathLexer.setPathData: The first parameter must be a string");
  this._pathData = pathData;
};
PathLexer.prototype.getNextToken = function () {
  var result = null;
  var d = this._pathData;
  while (result == null) {
    if (d == null || d == "") {
      result = new PathToken(PathToken.EOD, "");
    } else if (d.match(/^([ \t\r\n,]+)/)) {
      d = d.substr(RegExp.$1.length);
    } else if (d.match(/^([AaCcHhLlMmQqSsTtVvZz])/)) {
      result = new PathToken(PathToken.COMMAND, RegExp.$1);
      d = d.substr(RegExp.$1.length);
    } else if (d.match(/^(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)/)) {
      result = new PathToken(PathToken.NUMBER, parseFloat(RegExp.$1));
      d = d.substr(RegExp.$1.length);
    } else {
      throw new Error("PathLexer.getNextToken: unrecognized path data " + d);
    }
  }
  this._pathData = d;
  return result;
};
PathToken.UNDEFINED = 0;
PathToken.COMMAND = 1;
PathToken.NUMBER = 2;
PathToken.EOD = 3;

function PathToken(type, text) {
  if (arguments.length > 0) {
    this.init(type, text);
  }
}

PathToken.prototype.init = function (type, text) {
  this.type = type;
  this.text = text;
};
PathToken.prototype.typeis = function (type) {
  return this.type == type;
}
